<template>
  <n-spin
    :class="[
      'ie-upload', {
        'ie-upload--image': props.isImage
      }
    ]"
    :show="loading"
  >
    <template v-if="props.isImage">
      <div
        class="ie-upload-mask"
        v-if="fileListRef.length && !loading"
        :style="{
          width: props.width + 'px',
          height: props.height + 'px'
        }"
      >
        <div class="ie-upload-mask__cover">
          <n-space>
            <n-icon size="20" @click="handlePreview">
              <eye-outlined />
            </n-icon>
            <n-icon size="20" @click="handleRemove">
              <delete-outlined />
            </n-icon>
          </n-space>
        </div>
        <n-image
          :src="fileListRef[0].url"
          :width="props.width"
          :height="props.height"
          ref="imageRef"
        />
      </div>
    </template>
    <template v-else>
      <n-tag
        v-if="fileListRef.length && !loading"
        @close="handleRemove"
        size="large"
        closable
      >{{ fileListRef[0].url }}</n-tag>
    </template>
    <n-upload
      v-show="fileListRef.length === 0 || loading"
      action="/api/upload"
      @finish="onUploadFinish"
      @before-upload="onBeforeUpload"
      :headers="getHeaders"
      v-model:file-list="fileListRef"
      :show-file-list="false"
      :accept="props.accept"
    >
      <n-button
        class="ie-upload-button"
        :style="props.isImage && {
          width: props.width + 'px',
          height: props.height + 'px'
        }"
        :dashed="props.isImage"
      >
        <n-icon v-if="props.isImage" size="32" depth="3" style="margin-bottom: 12px;">
          <cloud-upload-outline />
        </n-icon>
        {{ props.btnText }}
      </n-button>
    </n-upload>
  </n-spin>
</template>

<script setup>
import { ref, watch } from 'vue'
import { getHeaders } from '/@/api'

import CloudUploadOutline from '@vicons/ionicons5/CloudUploadOutline'
import EyeOutlined from '@vicons/antd/EyeOutlined'
import DeleteOutlined from '@vicons/antd/DeleteOutlined'

const props = defineProps({
  value: {
    type: [String, Array],
    default: null
  },
  accept: {
    type: String,
    default: 'image/*'
  },
  isImage: {
    type: Boolean,
    default: true
  },
  width: {
    type: Number,
    default: 120
  },
  height: {
    type: Number,
    default: 120
  },
  btnText: {
    type: String,
    default: '上传文件'
  }
})

const emit = defineEmits([
  'update:value',
  'change'
])

const loading = ref(false)
const fileListRef = ref([])
const imageRef = ref()

const isMultiple = Array.isArray(props.value)

watch(
  () => props.value,
  value => {
    if (isMultiple && value.length) {
      fileListRef.value = value.map(url => ({
        id: Date.now(),
        name: Date.now(),
        status: 'finished',
        url
      }))
    } else if (!isMultiple && value) {
      fileListRef.value = [{
        id: Date.now(),
        name: Date.now(),
        status: 'finished',
        url: value
      }]
    }
  }, { immediate: true }
)

function onBeforeUpload() {
  loading.value = true
}

function onUploadFinish({ file, event }) {
  try {
    event = JSON.parse(event.target.response)
  } catch (err) {}

  if (event.code === 0) {
    file.url = event.data.filepath
    file.rawResponse = event.data

    emit('update:value', file.url)
    emit('change', event.data)
  }

  loading.value = false
}

function handlePreview() {
  imageRef.value?.click()
}

function handleRemove() {
  fileListRef.value = []
  emit('update:value', null)
  emit('change', null)
}
</script>

<style lang="less">
.ie-upload {
  line-height: 0;

  &-button {
    background-color: #fafafa;

    .n-button__content {
      font-size: 13px;
      flex-direction: column;
    }
  }

  &.ie-upload--image {

    .n-button:not(.n-button--disabled):hover {
      color: var(--text-color);
    }
  }

  &-mask {
    position: relative;
    border-radius: 3px;
    overflow: hidden;

    &:hover .ie-upload-mask__cover {
      opacity: 1;
    }

    &__cover {
      position: absolute;
      top: 0;
      left: 0;
      z-index: 1;
      width: 100%;
      height: 100%;
      background-color: rgba(0,0,0,.5);
      opacity: 0;
      transition: all .3s;
      display: flex;
      justify-content: center;
      align-items: center;

      .n-space {
        z-index: 99;

        .n-icon {
          color: #fff;
          opacity: .8;
          transition: all .3s;
          cursor: pointer;

          &:hover {
            opacity: 1;
          }
        }
      }
    }
  }
}
</style>